package ast

type ModifierFunc func(Node) Node

//Modify 通过这个函数可以对ast树上的所有节点都执行相应的ModifierFunc函数操作
func Modify(node Node,modifier ModifierFunc) Node{
	switch node := node.(type){
	/*对 ast.Modify 递归调用的一个效果是，作为调用参数的节点会替换成调用返回
的节点。*/
	case *Program:
		for i,statement := range node.Statements{
			node.Statements[i],_ = Modify(statement,modifier).(Statement)
		}
	case *ExpressionStatement:
		node.Expression,_ = Modify(node.Expression,modifier).(Expression)
	case *InfixExpression:
		node.Left,_ = Modify(node.Left,modifier).(Expression)
		node.Right,_ = Modify(node.Right,modifier).(Expression)
	case *PrefixExpression:
		node.Right,_ = Modify(node.Right,modifier).(Expression)
	case *IndexExpression:
		node.Left,_ = Modify(node.Left,modifier).(Expression)
		node.Index,_ = Modify(node.Index,modifier).(Expression)
	case *IfExpression:
		node.Condition,_ = Modify(node.Condition,modifier).(Expression)
		node.Consequence,_ = Modify(node.Consequence,modifier).(*BlockStatement)
		if node.Alternative != nil{
			node.Alternative,_ = Modify(node.Alternative,modifier).(*BlockStatement)
		}
	case *BlockStatement:
		for i,_ := range node.Statements{
			node.Statements[i],_ = Modify(node.Statements[i],modifier).(Statement)
		}
	case *ReturnStatement:
		node.ReturnValue,_ = Modify(node.ReturnValue,modifier).(Expression)
	case *LetStatement:
		node.Value,_ = Modify(node.Value,modifier).(Expression)
	case *FunctionLiteral:
		for i,_ := range node.Parameters{
			node.Parameters[i],_ = Modify(node.Parameters[i],modifier).(*Identifier)
		}
		node.Body,_ = Modify(node.Body,modifier).(*BlockStatement)
	case *ArrayLiteral:
		for i,_ := range node.Elements{
			node.Elements[i],_ = Modify(node.Elements[i],modifier).(Expression)
		}
	case *HashLiteral:
		for key,value := range node.Pairs{
			key,_ = Modify(key,modifier).(Expression)
			value,_ = Modify(value,modifier).(Expression) 
		}
		//源码这里是新建一个map，再来一一映射，我直接在源map表里面映射
	}
/*第一是递归遍历给定 ast.Node 的子节点。这就是 switch 语句中发生的事情，之
前我们已经从 Eval 函数中了解过这种机制。但是某些 ast.Node 没有也不会有自己的
case 分支，例如*ast.IntegerLiteral，因为这些节点没有子节点，无法进行遍历。
如果某节点有子节点，就像*ast.Program 一样，我们会对每个子节点调用 ast.Modify，
然后对子节点的子节点继续调用 ast.Modify，依此类推。这就是递归。*/
/*在 ast.Modify 的最后一行，用得到的 Node 调用了 modifier，然后返回了结果。
这点很重要。如果只调用 modifier(node)然后执行 return node，那么只是修改了节
点，而没有替换 AST 中的节点。
最后一行的另一个作用是停止递归*/
	return modifier(node)
}
/*目前
ast.Modify只是修改了子节点，不更新父节点的Token字段。这会导致节点的String()
方法输出的信息与节点不一致，甚至出现其他错误。*/